/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "MindWaveMobile.h"
#include "core/shader_built_in_functions.h"


#include <Windows.h>
#include <thread>
#include <mutex>


static HANDLE hSerial = INVALID_HANDLE_VALUE;


static std::thread	g_Threads;
static std::mutex	g_读写锁;
static bool g轮询 = true;


static float32	g采样数据[4096] = {};
static uint32	g采样数量 = 0;

// 定义同步字节和扩展代码字节
#define SYNC   0xAA
#define EXCODE 0x55
#define PARSER_CODE_BATTERY 0x01


class C_串口通信 {

public:
	C_串口通信() {
		
	}
	~C_串口通信() {
		//if (hSerial != INVALID_HANDLE_VALUE) {
		//	CloseHandle(hSerial);
		//	
		//}
		CloseHandle(hSerial);
		hSerial = INVALID_HANDLE_VALUE;

		std::cout << "关闭串口" << std::endl;
	}

	bool f_打开串口(const char* port_name) {
		
		try {
			// 创建串行端口句柄

			hSerial = CreateFileA(
				port_name,
				GENERIC_READ,
				FILE_SHARE_READ,
				0,
				OPEN_EXISTING,
				0,
				0
			);

			//CloseHandle(hSerial);

			if (hSerial == INVALID_HANDLE_VALUE) {
				fprintf(stderr, "打开串口出错 %s\n", port_name);
				//CloseHandle(hSerial);
				//hSerial = 0;
				return false;
			}

			// 配置串行端口参数
			DCB dcbSerialParams = { 0 };
			dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
			if (!GetCommState(hSerial, &dcbSerialParams)) {
				fprintf(stderr, "获取串行端口状态时出错 %s\n", port_name);
				//CloseHandle(hSerial);
				//hSerial = 0;
				return false;
			}

			// 设置波特率、数据位、停止位和奇偶校验位
			dcbSerialParams.BaudRate = CBR_115200;	// 设置为57600波特率
			//dcbSerialParams.ByteSize = 8;           // 数据位为8位
			//dcbSerialParams.StopBits = ONESTOPBIT;  // 停止位为1位
			//dcbSerialParams.Parity = NOPARITY;      // 无奇偶校验

			//dcbSerialParams.fOutxCtsFlow = false;
			//dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
			//dcbSerialParams.fOutX = false;
			//dcbSerialParams.fInX = false;

			if (!SetCommState(hSerial, &dcbSerialParams)) {
				fprintf(stderr, "设置串行端口状态时出错 %s\n", port_name);
				CloseHandle(hSerial);
				hSerial = INVALID_HANDLE_VALUE;
				return false;
			}

			COMMTIMEOUTS timeouts = { 0 };
			timeouts.ReadIntervalTimeout = 100;
			timeouts.ReadTotalTimeoutConstant = 100;
			timeouts.ReadTotalTimeoutMultiplier = 10;
			timeouts.WriteTotalTimeoutConstant = 0;
			timeouts.WriteTotalTimeoutMultiplier = 0;
			//SetCommTimeouts(hSerial, &timeouts);

			return true;
		}
		catch (const std::exception& e) {
			// 异常处理
			std::cerr << "Exception occurred: " << e.what() << std::endl;

			//if (hSerial != INVALID_HANDLE_VALUE) {
			//	CloseHandle(hSerial);
			//	
			//}
			CloseHandle(hSerial);
			hSerial = INVALID_HANDLE_VALUE;
			return false;
		}

		return true;
	}
};

static C_串口通信* g串口 = nullptr;


int parsePayload(unsigned char* payload, unsigned char pLength) {

	unsigned char bytesParsed = 0;
	unsigned char code;
	unsigned char length;
	unsigned char extendedCodeLevel;
	int i;

	/* Loop until all bytes are parsed from the payload[] array... */
	while (bytesParsed < pLength) {

		/* Parse the extendedCodeLevel, code, and length */
		extendedCodeLevel = 0;
		while (payload[bytesParsed] == EXCODE) {
			extendedCodeLevel++;
			bytesParsed++;
		}
		code = payload[bytesParsed++];
		if (code & 0x80) length = payload[bytesParsed++];
		else              length = 1;


		if (code & 0x80) {
			if (length == 2) {
				int16 rawValue = (payload[bytesParsed] << 8) | payload[bytesParsed + 1];
				//std::cout<<"rawValue"<< rawValue << "\n";

				g采样数据[g采样数量] = clamp(rawValue / 1000.0, -1, 1);
				g采样数量 >= 4095 ? g采样数量 = 0 : ++g采样数量;
			}
		}
		else {
			if (payload[bytesParsed] == PARSER_CODE_BATTERY && bytesParsed + 1 < pLength) {
				uint8 batteryLevel = payload[bytesParsed + 1];
				std::cout << "电量" << int32(batteryLevel) << "\n";
			}
		}

		//printf("EXCODE level: %d CODE: 0x%02X length: %d\n",
		//	extendedCodeLevel, code, length);
		//printf("Data value(s):");
		//for (i = 0; i < length; i++) {
		//	printf(" %02X", payload[bytesParsed + i] & 0xFF);
		//}
		//printf("\n");

		/* Increment the bytesParsed by the length of the Data Value */
		bytesParsed += length;
	}

	return(0);
}



void f_读流数据() {
	// 读取串行端口数据
	uint8 buffer[256];
	DWORD bytesRead = 1;
	OVERLAPPED Overlapped = { 0 };

	uint8 c = 0;
	uint32 i = 0;

	for ( ; g轮询; ) {
		//std::this_thread::sleep_for(std::chrono::milliseconds(1));

		DWORD error = ReadFile(hSerial, &c, 1, &bytesRead, nullptr);
		//std::cout << "c = " << int32(c) << " " << error << " bytesRead = " << bytesRead << "\n";

		if (c != SYNC) continue;
		ReadFile(hSerial, &c, sizeof(c), &bytesRead, nullptr);
		if (c != SYNC) continue;


		uint8 字节数 = 0;
		for (;;) {
			ReadFile(hSerial, &字节数, sizeof(c), &bytesRead, nullptr);
			if (字节数 != 170) break;
		}
		if (字节数 > 169) continue;


		
		ReadFile(hSerial, buffer, sizeof(uint8) * 字节数, &bytesRead, nullptr);


		uint32 checksum = 0;
		for (i = 0; i < 字节数; i++) checksum += buffer[i];
		checksum &= 0xFF;
		checksum = ~checksum & 0xFF;


		/* Parse [CKSUM] byte */
		ReadFile(hSerial, &c, sizeof(c), &bytesRead, nullptr);
		
		/* Verify [PAYLOAD...] chksum against [CKSUM] */
		if (c != checksum) continue;

		g_读写锁.lock();
		parsePayload(buffer, 字节数);
		g_读写锁.unlock();
		//std::cout<<"读流数据 \n";
	}
}





bool f_input_打开设备() {
	if (!g串口) {
		g串口 = new C_串口通信();

		char port_name[5] = "COM0";
		port_name[4] = '\0';
		for (uint32 i = 0; i < 10; ++i) {
			port_name[3] = 48 + i;
			if (g串口->f_打开串口(port_name)) {
				std::cout<<"连接成功"<<std::endl;
				break;
			}
		}
	}

	g_Threads = std::thread(f_读流数据);
	//g_Threads.detach();
	return true;
}

void f_input_关闭设备() {
	//g轮询 = false;
	//g_Threads.join();
	g轮询 = false;
	
	if (g_Threads.joinable()) {
		g_Threads.join();
		//CloseHandle(hSerial);
	}

	delete g串口;
}

float32* f_input_get脑波数据(uint32& 通道数量) {
	通道数量 = 1;
	return &g采样数据[g采样数量];
}

void f_input_get脑波数据(std::vector<float32>& data, uint32 要取得的数量) {
	g_读写锁.lock();

	要取得的数量 = min(要取得的数量, g采样数量);
	data.resize(要取得的数量);

	memcpy(data.data(), g采样数据, 要取得的数量 * sizeof(float32));

	g采样数量 = (g采样数量 - 要取得的数量);
	memcpy(g采样数据, &g采样数据[要取得的数量], g采样数量 * sizeof(float32));

	g_读写锁.unlock();
}

